<!--  -->
<template>
  <el-container>
    <el-main>
      <div style="height: 100%">
        <div ref="global_trace_content" id="global_trace_content"></div>
      </div>
    </el-main>

    <div
      v-show="isShowNodeMenuPanel"  ref="isShowNodeMenuPanel"
      :style="{ left: nodeMenuPanelPosition.x + 'px', top: nodeMenuPanelPosition.y + 'px', }"
      style=" z-index: 999; padding: 10px; background-color: #ffffff; border: #eeeeee solid 1px; box-shadow: 0px 0px 8px #cccccc; position: absolute; border-radius: 10px; "
    >
      <div style=" line-height: 25px; padding-left: 10px; color: #888888; font-size: 12px; " > 对这个节点进行操作： </div>
      <div class="c-node-menu-item" @click.stop="doAction('1')">
        查看详情
      </div>
      <div class="c-node-menu-item" @click.stop="doAction('2')">展开此节点</div>
      <div class="c-node-menu-item" @click.stop="doAction('操作1')">操作3</div>
      <div class="c-node-menu-item" @click.stop="doAction('操作1')">操作4</div>
    </div>
    <div
            v-show="isShowInfo"
            class="c-my-panel"
            style="width: 200px"
          >
            <el-card :body-style="{ padding: '0px' }">
              <div slot="header" class="clearfix">
                <span>{{currentNode.label}}</span>
           
            </div>
              <img v-if="currentNode&&currentNode.image" style="width: 100%;"
                :src="currentNode.image" class="image"
              />
              <div style="padding: 14px">
                <span v-if="currentNode">{{currentNode.info}}</span>
                <!-- <div class="bottom clearfix">
                  <time class="time">{{ currentDate }}</time>
                   <el-button type="text" class="button">操作按钮</el-button> 
                </div> -->
              </div>
            </el-card>
          </div>

          <div style=" position: absolute; z-index: 700; left: 20px; top: 20px;  padding-top: 6px; padding-left: 30px; border: #efefef solid 1px; color: #555555; border-radius: 10px; background-color: rgba(255, 255, 255, 0.79); font-size: 12px; " >

            <el-tabs type="border-card">
  <el-tab-pane>
    <span slot="label"> 节点查询</span>
    <el-form :inline="true" :model="formInline.searchval" class="demo-form-inline">
  <el-form-item label="节点">
    <el-input v-model="formInline.searchval" placeholder="节点"></el-input>
  </el-form-item>

  <el-form-item>
    <el-button type="primary" @click="onSubmitval">查询</el-button>
  </el-form-item>
</el-form>
  </el-tab-pane>
  <el-tab-pane label="关系查询">
    <el-form  :model="formInline" class="demo-form-inline">
  <el-form-item label="">
    <el-input v-model="formInline.startnode" placeholder="开始节点"></el-input>
  </el-form-item>
  <el-form-item label="">
    <el-input v-model="formInline.endnode" placeholder="开始节点"></el-input>
  </el-form-item>
  <el-form-item label="关系属性" prop="type">
    <el-radio-group v-model="formInline.radio">
    <el-radio :label="3">最短路径</el-radio>
    <el-radio :label="6">备选项</el-radio>
    <el-radio :label="9">备选项</el-radio>
  </el-radio-group>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" @click="onSubmit">查询</el-button>
  </el-form-item>
</el-form>
  </el-tab-pane>
  <el-tab-pane label="角色管理">角色管理</el-tab-pane>
</el-tabs>
      
          </div>
  </el-container>


</template>

<script>
const vis = require('vis-network/dist/vis-network.min.js')
require('vis-network/dist/dist/vis-network.min.css')

export default {
  name: "",
  components: {},
  props: [],
  data() {
    return {
      currentNode: {
       
      },
      formInline: {
        startnode: '',
        endnode: '',
        radio:3,
        searchval:''
        },
      currentNodeimageUrl:"",
      nodeMenuPanelPosition: { x: 0, y: 0 },
      isShowNodeMenuPanel:false,
      isShowInfo:false,
      protocol: "bolt",
      searchval: "",
      host: "172.16.218.125",
      port: 7687,
      username: "neo4j",
      password: "123456",
      nodes: [],
      edges: [],
      labels: [],
      loadGraphOption:{},
      visnodes :new vis.DataSet([]),
            // 创建连线对象
      visedges : new vis.DataSet([]),
    };
  },
  computed: {},
  watch: {},
  created() {},
  mounted() {
    
    this.initneo4j();
   
  },
  methods: {
    connect() {
      return this.$neo4j
        .connect(
          this.protocol, this.host, this.port, this.username, this.password
        )
        .then((driver) => {
          // Update the context of your app
        });
    },

    toNumber({ low, high }) {
        let res = high
        for (let i = 0; i < 32; i++) {
          res *= 2
        }
        return low + res
     },  

     onSubmit() {
      this.formInline.searchval='';
      this.initneo4j()
      },
      onSubmitval(){
        this.formInline.startnode='';
        this.formInline.endnode='';
        this.initneo4j()
      },
    initneo4j() {
      this.connect();
      let cypher = `match p=(n)-[r]->()     return  p `;
      if (this.formInline.searchval) {
        cypher = `match p=(n)-[r]->(m) where n.name='${this.formInline.searchval}'  return  p  `;
      }
      if(this.formInline.startnode&&this.formInline.endnode){
        cypher = `match p = shortestpath((a)<-[r*0..4]->(b)) where a.name = '${this.formInline.startnode}' and b.name='${this.formInline.endnode}' return p`
      }
      this.$neo4j.run(cypher).then((res) => {
          console.log("555", res);
          let records = res.records;
          let nodes = new Set();
          let visedges =[];
          this.nodesRelation = [];
          var dir = "http://localhost:805/photo/";
          for (let i = 0; i < records.length; i++) {

           for(let j=0;j< records[i]._fields[0].segments.length;j++){
            var  nodestart= records[i]._fields[0].segments[j].start.properties;
           
            if(nodestart.image !== undefined && nodestart.image != "")
            {
            
              nodes.add({
              id: records[i]._fields[0].segments[j].start.properties.name,
              label: records[i]._fields[0].segments[j].start.properties.name,
              value: records[i]._fields[0].segments[j].start.properties.value,
              shape:'circularImage',
              group:records[i]._fields[0].segments[j].start.properties.categories,
              image:dir+records[i]._fields[0].segments[j].start.properties.name+".jpg",
              info: records[i]._fields[0].segments[j].start.properties.info,
              
            }
          );
            }
            else{
            nodes.add({
              id: records[i]._fields[0].segments[j].start.properties.name,
              label: records[i]._fields[0].segments[j].start.properties.name,
              value: records[i]._fields[0].segments[j].start.properties.value,
              group:records[i]._fields[0].segments[j].start.properties.categories,
             
              info: records[i]._fields[0].segments[j].start.properties.info,
             
            });
          }
          var  nodesend= records[i]._fields[0].segments[j].end.properties;
        
          if(nodesend.image !== undefined && nodesend.image != ""){
            nodes.add({
              id: records[i]._fields[0].segments[j].end.properties.name,
              label: records[i]._fields[0].segments[j].end.properties.name,
              value: records[i]._fields[0].segments[j].end.properties.value,
              group:records[i]._fields[0].segments[j].end.properties.categories,
              shape:'circularImage',
              image:dir +records[i]._fields[0].segments[j].end.properties.name +".jpg",
             
                info: records[i]._fields[0].segments[j].end.properties.info,
              
            });
          }
          else{
            nodes.add({
              id: records[i]._fields[0].segments[j].end.properties.name,
              label: records[i]._fields[0].segments[j].end.properties.name,
              value: records[i]._fields[0].segments[j].end.properties.value,
              group:records[i]._fields[0].segments[j].end.properties.categories,
              info: records[i]._fields[0].segments[j].end.properties.info,
              
            });
          }
      
          visedges.push({
              id:this.toNumber( records[i]._fields[0].segments[j].relationship.identity),
              from: records[i]._fields[0].segments[j].start.properties.name,
              to: records[i]._fields[0].segments[j].end.properties.name,
              label: records[i]._fields[0].segments[j].relationship.type,
            });
          }

          
        }

         this.edges=visedges
          // this.datalist.lines = this.nodesRelation;
          console.log("edges", this.edges);
         
            let map = new Map();
            for (let item of nodes) {
                if (!map.has(item.id)) {
                    map.set(item.id, item);
                }
            }
            this.nodes= [...map.values()];
          
          console.log("node",  this.nodes);
          this.globalTrace(this.nodes,  this.edges);
        })
        .then(() => {});
    },

    loadChildNodesFromRemoteServer(nodetext,callback){
     
     var cypher = `match p=(n)<-[r]->(m) where n.name='${nodetext}'  return  p  `;
      this.$neo4j.run(cypher).then((res) => {
        let records = res.records;
          
          let nodes = new Set();
        var dir = "http://localhost:805/photo/";
        var  cc={ 
          nodes: [],
      // 边集
          edges: []
        };
          for (let i = 0; i < records.length; i++) {
            for(let j=0;j< records[i]._fields[0].segments.length;j++){
            var  nodestart= records[i]._fields[0].segments[j].start.properties;
          
            if(nodestart.image !== undefined && nodestart.image != "")
            {
            
              nodes.add({
              id: records[i]._fields[0].segments[j].start.properties.name,
              label: records[i]._fields[0].segments[j].start.properties.name,
              value: records[i]._fields[0].segments[j].start.properties.value,
              shape:'circularImage',
              group:records[i]._fields[0].segments[j].start.properties.categories,
              image:dir+records[i]._fields[0].segments[j].start.properties.name+".jpg",
              info: records[i]._fields[0].segments[j].start.properties.info,
              
            }
          );
            }
            else{
            nodes.add({
              id: records[i]._fields[0].segments[j].start.properties.name,
              label: records[i]._fields[0].segments[j].start.properties.name,
              value: records[i]._fields[0].segments[j].start.properties.value,
              group:records[i]._fields[0].segments[j].start.properties.categories,
              info: records[i]._fields[0].segments[j].start.properties.info,
            });
          }
          var  nodesend= records[i]._fields[0].segments[j].end.properties;
        
          if(nodesend.image !== undefined && nodesend.image != ""){
            nodes.add({
              id: records[i]._fields[0].segments[j].end.properties.name,
              label: records[i]._fields[0].segments[j].end.properties.name,
              value: records[i]._fields[0].segments[j].end.properties.value,
              group:records[i]._fields[0].segments[j].end.properties.categories,
              shape:'circularImage',
              image:dir +records[i]._fields[0].segments[j].end.properties.name +".jpg",
             
                info: records[i]._fields[0].segments[j].end.properties.info,
              
            });
          }
          else{
            nodes.add({
              id: records[i]._fields[0].segments[j].end.properties.name,
              label: records[i]._fields[0].segments[j].end.properties.name,
              value: records[i]._fields[0].segments[j].end.properties.value,
              group:records[i]._fields[0].segments[j].end.properties.categories,
              
                info: records[i]._fields[0].segments[j].end.properties.info,
              
            });
          }
            cc.nodes=nodes;
            cc.edges.push({
              id:this.toNumber( records[i]._fields[0].segments[j].relationship.identity),
              from: records[i]._fields[0].segments[j].start.properties.name,
              to: records[i]._fields[0].segments[j].end.properties.name,
              label: records[i]._fields[0].segments[j].relationship.type,
            });
          }
        }
          // this.datalist.lines = this.nodesRelation;
          console.log("this.nodesRelation", this.nodesRelation);
         
            let map = new Map();
            for (let item of nodes) {
                if (!map.has(item.id)) {
                    map.set(item.id, item);
                }
            }
            cc.nodes= [...map.values()];      
         this.createNetwork(cc)
       
       
      })
      .then(() => {});
  },
  //扩展节点 param nodes和relation集合
   deleteValueFromArr(arrName,field,keyValue){
		    if(arrName==null || arrName.length==0){
		        return null;
		    }
		    for (var i =0;i< arrName.length;i++){
		        if(arrName[i][field]==keyValue){
		            arrName.splice(i,1);
		        }
		    }
		    return arrName;
		},
		//根据对象数组中的某个属性值获取过滤后的数组
		//arrName数组名  field过滤的字段   keyValue字段值
		 getArrFromArr(arrName,field,keyValue){
		    var arrReturn=[];
		    if(arrName==null || arrName.length==0){
		        return arrReturn;
		    }
		    var obj;
		    for (var item=0; item< arrName.length;item++){
		        obj=arrName[item];
		        if(obj[field]==keyValue){
		            arrReturn.push(obj);
		        }
		    }
		    return arrReturn;
		},
    search() {
      this.initneo4j();
    },
 createNetwork(param) {
    //可以试试注释掉去重的方法看看效果
    if(param.nodes && param.nodes.length>0){
      
        //去除已存在的节点  以“label”属性为例删除重复节点，根据具体的属性自行修改
        for(var i in this.nodes){
            var nodeTemp = this.nodes[i];
            param.nodes = this.deleteValueFromArr(param.nodes,"id",nodeTemp.id);
        }
    }
    //添加节点
    for(var i=0;i<param.nodes.length;i++){
        var node = param.nodes[i];
      
        //除了固定的参数外，可以自己增加额外的参数
      
        this.nodes.push(node);
        this.visnodes.add(node);
    }
   
    if(param.edges && param.edges.length>0){
        //去除已存在的关系  以“label”属性为例删除重复节点，根据具体的属性自行修改
        for(var i in this.edges){
            var edgeTemp = this.edges[i];
            param.edges = this.deleteValueFromArr(param.edges,"id",edgeTemp.id);
        }
    }
    //添加关系

    for(var i=0;i<param.edges.length;i++){
        var edge = param.edges[i];
        this.edges.push(edge);
        this.visedges.add(edge)
    }
},
    globalTrace(nodes, edges) {
      // create an array with nodes
      this.visnodes = new vis.DataSet(nodes);
     
      // create an array with edges
      this.visedges = new vis.DataSet(edges);

      
      // create a this.network
      var container = document.querySelector("#global_trace_content");

//       let scale = {
//     min: 1,
//     max: 1000,
//     customScalingFunction(min?: number, max?: number, total?: number, value?: number): number {
//         return Math.max(0,value/999);
//     }
// }

      // provide the data in the vis format
      var data = {
        nodes: this.visnodes,
        edges:  this.visedges,
      };
      var options = {
       // canvasBackground: "#FFFF",

        physics: {
          stabilization: false,
                solver: 'forceAtlas2Based',
                barnesHut: {
                    gravitationalConstant: -80000,
                    springConstant: 0.001,
                    springLength: 200
                },
                forceAtlas2Based: {
                    gravitationalConstant: -50,
                    centralGravity: 0.003,
                    springLength: 230,
                    springConstant: 0.18
                },
        },
        interaction: {
                tooltipDelay: 200,
                hover: true,
                hideEdgesOnDrag: true,
                selectable: true,
                // navigationButtons: true,
                //selectConnectedEdges: false,
            },
        nodes: {
                borderWidth: 0,
                shape: 'dot',
              //  scaling: scale,
                font: {
                    size: 14,
                    strokeWidth: 7
                },

                scaling: {
      min: 1,
      max: 1000,
      // label: {
      //   enabled: false,
      //   min: 14,
      //   max: 30,
      //   maxVisible: 30,
      //   drawThreshold: 5
      // },
      customScalingFunction: function (min,max,total,value) {
        if (max === min) {
          return 0.5;
        }
        else {
          let scale = 1 / (max - min);
          return Math.max(0,value/999);
        }
      }
    },
            },
            // manipulation: {
            // enabled: true,
           
              
            //  },
            edges: {
                width: 0.02,
                font: {
                    size: 12,
                    color: '3cc5e7',
                },
                color: {
                    inherit: 'to',
                    opacity: 1,
                    color: '#cccccc',
                    highlight: '#3cc5e7',
                    hover: '#3cc5e7',
                },
                selectionWidth: 1,
                hoverWidth: 1,
                arrows: {
                    to: {
                        enabled: true,
                        scaleFactor: 0.5,
                    }
                },
                smooth: {
                    enabled: true,
                    type: 'continuous',
                    roundness: 0.5,
                }
            },
 
      
      };
  
     
      // initialize your this.network!
      this.network = new vis.Network(container, data, options);
      // this.this.network.on("click",e=> this.showDetail(e));//单击事件
      // this.this.network.on("doubleClick",e=> this.enterService(e))//双击事件

      this.network.moveTo({
  scale: 1,
  animation: {
    duration: 1000, // 动画持续时间（毫秒）
    easingFunction: 'easeInOutQuad' // 动画的缓动函数
  }
});
      const that=this;
      this.network.on("click", function (params) {
        params.event = "[original event]";
       
        that.isShowNodeMenuPanel=false
        console.log(
          "click event, getNodeAt returns: " +
            this.getNodeAt(params.pointer.DOM)
        );
       if( this.getNodeAt(params.pointer.DOM)=="undefined"|| this.getNodeAt(params.pointer.DOM)==undefined){
        that.isShowInfo=false
       }
        
      });
      this.network.on("doubleClick", function (params) {
        let node= this.getNodeAt(params.pointer.DOM)
        params.event = "[original event]";
        console.log("doubleClick",node)
        that.isShowInfo=false
        that.loadChildNodesFromRemoteServer(node)
      });
      this.network.on("oncontext", function (params) {
       
       //that.isShowNodeMenuPanel=true
        let node= this.getNodeAt(params.pointer.DOM)

     
      //console.log(node)
    
       
       
      });
      this.network.on("dragStart", function (params) {
        // There's no point in displaying this event on screen, it gets immediately overwritten
        params.event = "[original event]";
        console.log("dragStart Event:", params);
        console.log(
          "dragStart event, getNodeAt returns: " +
            this.getNodeAt(params.pointer.DOM)
        );
       
      });
    
      this.network.on("showPopup", function (params) {
     
    
      });
      this.network.on("hidePopup", function () {
        console.log("hidePopup Event");
      });
      this.network.on("select", function (params) {
        console.log("select Event:", params);
      });
      this.network.on("selectNode", function (params) {
        console.log("selectNode Event:", params);
        that.currentNode=that.nodes.filter(item=>item.id=== this.getNodeAt(params.pointer.DOM))[0]
          that.isShowInfo=true
          console.log("currentNode", that.currentNode)
      });
      this.network.on("selectEdge", function (params) {
        console.log("selectEdge Event:", params);
      });
      this.network.on("deselectNode", function (params) {
        console.log("deselectNode Event:", params);
      });
      this.network.on("deselectEdge", function (params) {
        console.log("deselectEdge Event:", params);
      });
      // this.network.on("hoverNode", function (params) {
      //   console.log("hoverNode Event:", params);
      // });
      // this.network.on("hoverEdge", function (params) {
      //   console.log("hoverEdge Event:", params);
      // });
      // this.network.on("blurNode", function (params) {
      //   console.log("blurNode Event:", params);
      // });
      // this.network.on("blurEdge", function (params) {
      //   console.log("blurEdge Event:", params);
      // });
    },
  },
};
</script>
<style lang='css' scoped>


#global_trace_content {
  width: 100vmax-20px;
  height: 900px;
  border: 1px solid lightgray;
}
.c-my-panel {
  position: absolute;
  left: 10px;
  top: 100px;
  border-radius: 10px;
  z-index: 800;
  background-color: #efefef;
  border: #eeeeee solid 1px;
  padding: 20px;
}
.c-option-name {
  color: #666666;
  font-size: 14px;
  line-height: 40px;
  padding-left: 10px;
  padding-right: 10px;
}
</style>